package com.apache.database.db.hibernate;

import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import com.apache.cache.service.CacheManager;
import com.apache.cache.service.impl.LoadCacheFactory;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;

import com.apache.database.constant.Validator;
import com.apache.database.db.BaseDao;
import com.apache.database.exception.DaoAccessException;
import com.apache.database.model.MethodParam;
import com.apache.database.model.Page;
import org.springframework.orm.hibernate5.HibernateCallback;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;

/**
 * description: hibernate 持久层的实现
 * 
 */
public class DaoHibernateImpl extends HibernateDaoSupport implements BaseDao {

	private CacheManager cache;

	public DaoHibernateImpl() {
		cache = LoadCacheFactory.getInstance().getCacheManager("");
	}

	public CacheManager getCache() {
		return cache;
	}

	/**
	 * description: 批量删除对象
	 * @return true为删除成功；false为删除失败
	 */
	public boolean deleteBath(MethodParam param) {
		List list = (List) param.getVaule();
		try {
			this.getHibernateTemplate().deleteAll(list);
		} catch (Exception e) {
			throw new DaoAccessException("执行deleteBath方法出错", e);
		}
		return true;
	}

	/**
	 * description: 批量修改对象值
	 * @return true为修改成功；false为修改失败
	 */
	public boolean editBath(MethodParam param) {
		List list = (List) param.getVaule();
		try {
			for (Object po : list) {
				this.getHibernateTemplate().update(po);
			}
		} catch (Exception e) {
			throw new DaoAccessException("执行editBath方法出错", e);
		}
		return true;
	}

	/**
	 * 
	 * description: 批量新增
	 * @return true为新增成功；false为新增失败
	 */
	public boolean insertBath(MethodParam param) {
		List list = (List) param.getVaule();
		try {
			//this.getHibernateTemplate().saveOrUpdateAll(list);
		} catch (Exception e) {
			throw new DaoAccessException("执行insertBath方法出错", e);
		}
		return true;
	}

	/**
	 * description: 获取指定sql的count值
	 * @param param 方法参数模型
	 * @return 返回sql执行的记录数
	 */
	public long count(MethodParam param) {
		int count = 0;
		Session session = null;
		try {
            session = getHibernateTemplate().getSessionFactory().openSession();
			Query query = session.createQuery(param.getSqlStr());
			getParamClass(query, param.getParams());
			Object obj = query.uniqueResult();
			if (Validator.isEmpty(obj))
				return 0;
			if ("List".equals(obj.getClass().getSimpleName())) {
				count = ((List) obj).size();
			} else {
				count = Integer.parseInt(obj.toString());
			}
		} catch(HibernateException e1){
            throw new DaoAccessException("执行count方法出错", e1);
        }catch (Exception e) {
			throw new DaoAccessException("执行count方法出错", e);
		} finally {
		    if(null != session) {
                session.flush();
                session.close();
            }
		}
		return count;
	}

	/**
	 * description: 删除指定对象
	 * @param param 方法参数模型
	 * @return true为删除成功；false为删除失败
	 */
	public boolean delete(MethodParam param) {
		try {
			if (Validator.isNotNull(param.getSqlStr())) {//用hql批量删除
				editOrDelForHql(param);
			} else {
				this.getHibernateTemplate().delete(param.getVaule());
				if (Validator.isNotNull(param.getCacheId())) {
					cache.removeCacheObject(param.getCacheId());
				}
			}
		} catch (Exception e) {
			throw new DaoAccessException("执行delete方法出错", e);
		}
		return true;
	}

	/**
	 * description: 修改对象值
	 * @param param 方法参数模型
	 * @return true为修改成功；false为修改失败
	 */
	public boolean edit(MethodParam param) {
		try {
			this.getHibernateTemplate().clear();
			if (Validator.isNotNull(param.getSqlStr())) {//用hql批量修改
				editOrDelForHql(param);
			} else {
				this.getHibernateTemplate().update(param.getVaule());
				if (Validator.isNotNull(param.getCacheId())) {
					cache.createCacheObject(param.getCacheId(), param.getVaule());
				}
			}
		} catch (Exception e) {
			throw new DaoAccessException("执行edit方法出错", e);
		}
		return true;
	}

	/**
	 * 
	 * description: 新增单个对象
	 * @param param 方法参数模型
	 * @return true为新增成功；false为新增失败
	 */
	public boolean insert(MethodParam param) {
		try {
			this.getHibernateTemplate().save(param.getVaule());
			if (Validator.isNotNull(param.getCacheId())) {
				cache.createCacheObject(param.getCacheId(), param.getVaule());
			}
		} catch (Exception e) {
			throw new DaoAccessException("执行insert方法出错", e);
		}
		return true;
	}

	/**
	 * description: 分页查询
	 * @param param 方法参数模型
	 * @return 返回page对象
	 */
	public Page pageSelect(MethodParam param) {
		Page page = new Page();
		int startResult = 0;
		if (param.getPageIndex() > 1) {
			startResult = param.getPageSize() * (param.getPageIndex() - 1);
		} else {
			startResult = 0;
		}
		page.setPageNeeded(param.getPageIndex());
		page.setPageSize(param.getPageSize());
		Session session = getHibernateTemplate().getSessionFactory().openSession();
		try {
			Query query = session.createQuery(param.getSqlStr());
			getParamClass(query, param.getParams());
			int rsCount = (int) param.getPageCount();
			if (rsCount == 0)
				rsCount = query.list().size();
			query.setFirstResult(startResult);
			query.setMaxResults(param.getPageSize());
			List list = query.list();
			if (!Validator.isEmpty(list)) {
				page.setPageObjects(list);
				page.setCount(rsCount);
			}
		} catch (Exception e) {
			throw new DaoAccessException("执行pageSelect方法出错", e);
		} finally {
			session.flush();
			session.close();
		}
		return page;
	}

	/**
	 * description: 列表查询
	 * @param param 方法参数模型
	 * @return 返回sql执行的结果集
	 */
	public List select(MethodParam param) {
		List list = null;
		Session session = getHibernateTemplate().getSessionFactory().openSession();
		try {
			Query query = session.createQuery(param.getSqlStr());
			getParamClass(query, param.getParams());
			list = query.list();
		} catch (Exception e) {
			throw new DaoAccessException("执行select方法出错", e);
		} finally {
			session.flush();
			session.close();
		}
		return list;
	}

	/**
	 * description: 获取唯一对象实例
	 * @param param 方法参数模型
	 * @return 返回sql执行后的数据对象
	 */
	public Object selectSingle(MethodParam param) {
		Session session = getHibernateTemplate().getSessionFactory().openSession();
		try {
			Object obj = null;
			if (Validator.isNotNull(param.getCacheId())) {
				obj = cache.getCacheCloneByKey(param.getCacheId());
			}
			if (Validator.isEmpty(obj)) {
				Query query = session.createQuery(param.getSqlStr());
				getParamClass(query, param.getParams());
				obj = query.uniqueResult();
			}
			return obj;
		} catch (Exception e) {
			throw new DaoAccessException("执行selectSingle方法出错", e);
		} finally {
			session.flush();
			session.close();
		}
	}

	public Object selectById(String spanceName, String key, String infoId, String cacheId) {
		Object obj = null;
		if (Validator.isNotNull(cacheId)) {
			obj = cache.getCacheCloneByKey(cacheId);
		}
		try {
			if (Validator.isEmpty(obj)) {
				obj = this.getHibernateTemplate().get(spanceName, infoId);
				if (!Validator.isEmpty(obj) && Validator.isNotNull(cacheId))
					cache.createCacheObject(cacheId, obj);
			}
		} catch (Exception e) {
			throw new DaoAccessException("执行selectById方法出错", e);
		}
		return obj;
	}

	private void getParamClass(Query query, Object... args) {
		if (Validator.isNull(args) || args.length <= 0) {
		} else {
			Class queryclass = query.getClass();
			for (int k = 0; k < args.length; k++) {
				try {
					Map<String, Object> map = (Map) args[k];
					for (String key : map.keySet()) {
						Object o = map.get(key);
						String oName = o.getClass().getSimpleName();
						Method qm = queryclass.getMethod("set" + oName, new Class[] { String.class, o.getClass() });
						//Method valueof = o.getClass().getMethod("valueOf", new Class[] { char[].class });
						if ("".equals(key))
							qm.invoke(query, k, String.valueOf(o));
						else
							qm.invoke(query, key, String.valueOf(o));
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	private int editOrDelForHql(final MethodParam param) throws Exception {
		int count = getHibernateTemplate().execute(new HibernateCallback<Integer>() {
			public Integer doInHibernate(Session session) throws HibernateException {
				Query query = session.createQuery(param.getSqlStr());
				getParamClass(query, param.getParams());
				Integer count = Integer.valueOf(query.executeUpdate());
				return count;
			}
		});
		return count;
	}

}
